/*
 * Copyright 2017 the original author or authors.
 */

package com.ivo.util;

import java.io.IOException;
import java.io.PrintWriter;
import java.security.Principal;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <h1>Web相关操作辅助类</h1>
 * <p>
 * content
 * </p>
 * <b>Note:</b>
 *
 * @author nexf
 * @since 2015/10/2 13:46
 */
public class WebUtil {

  private final static Logger logger = LoggerFactory.getLogger(WebUtil.class);

  /**
   * /** 通过request得到session, 不自动创建新session
   *
   * @param request 请求对象
   * @return 会话
   */
  public static HttpSession getSession(HttpServletRequest request) {
    return request.getSession(false);
  }

  /**
   * 获得session范围内的属性值
   *
   * @param request 请求对象
   * @param name 属性名
   * @return 属性值
   */
  public static Object getSessionAttribute(HttpServletRequest request, String name) {
    HttpSession session = getSession(request);
    return session == null ? null : session.getAttribute(name);
  }

  /**
   * 设定session范围内的属性值
   *
   * @param request 请求对象
   * @param name 属性名
   * @param value 属性值
   */
  public static void setSessionAttribute(HttpServletRequest request, String name, Object value) {
    HttpSession session = getSession(request);
    if (session == null) {
      session = request.getSession();
      logger.debug("no session on set key: {" + name + "}, value: {" + value
          + "}, create it, id is {" + session.getId() + "}");
    }
    session.setAttribute(name, value);

  }

  /**
   * 制作重定向url
   *
   * @param request 请求对象
   * @param relativeUrl 相对路径
   * @return url
   */
  public static String makeUrl(HttpServletRequest request, String relativeUrl) {
    return makeUrl(request, relativeUrl, null);
  }

  /**
   * 制作重定向url
   *
   * @param request request
   * @param relativeUrl 相对路径
   * @param queryString 查询字符串
   * @return url
   */
  public static String makeUrl(HttpServletRequest request, String relativeUrl, String queryString) {
    if (request == null) {
      return null;
    }
    if (relativeUrl != null) {
      relativeUrl = relativeUrl.trim();
    }
    if (queryString != null) {
      queryString = queryString.trim();
    }
    StringBuilder sb = new StringBuilder();
    sb.append(getApplicationPath(request));
    if (relativeUrl == null || relativeUrl.equals("")) {
      if (queryString != null && !queryString.trim().equals("")) {
        sb.append('?').append(queryString);
      }
    } else {
      if (relativeUrl.charAt(0) != '/') {
        sb.append('/');
      }
      sb.append(relativeUrl);
      if (queryString != null && !queryString.trim().equals("")) {
        sb.append('?').append(queryString);
      }
    }
    return sb.toString();
  }

  /**
   * 获取 系统应用 名
   *
   * @param request 请求对象
   * @return 路径
   */
  public static String getApplication(HttpServletRequest request) {
    return request.getContextPath();
  }

  /**
   * 获取 系统应用 路径
   *
   * @param request 请求对象
   * @return 路径
   */
  public static String getApplicationPath(HttpServletRequest request) {
    String application = getApplication(request);
    return getHostPath(request) + application;
  }

  /**
   * 获取 系统host路径
   *
   * @param request 请求对象
   * @return 路径
   */
  public static String getHostPath(HttpServletRequest request) {
    String scheme = request.getScheme();
    String serverName = request.getServerName();
    int serverPort = request.getServerPort();
    return scheme + "://" + serverName + ":" + serverPort;
  }

  /**
   * 获取request来源url
   *
   * @param request 请求对象
   * @return url
   */
  public static String getCurrentUrl(HttpServletRequest request) {
    if (request == null) {
      return null;
    }
    String url = request.getRequestURL().toString();
    String queryString = request.getQueryString();
    if (queryString != null) {
      url = url + "?" + queryString;
    }
    return url;
  }

  /**
   * 获取相对请求路径
   *
   * @param request 请求对象
   * @return 相对请求路径
   */
  public static String getRelativeURI(HttpServletRequest request) {
    String requestURI = request.getRequestURI();
    String contextPath = getApplication(request);
    if (contextPath != null && requestURI.startsWith(contextPath)) {
      requestURI = requestURI.substring(contextPath.length());
      if (!requestURI.startsWith("/")) {
        requestURI = "/" + requestURI;
      }
    }
    return requestURI;
  }

  /**
   * 获取用户代理字符串
   *
   * @param request 请求对象
   * @return 浏览器字符串
   */
  public static String getUserAgent(HttpServletRequest request) {
    String userAgent = request.getHeader("user-agent");
    return userAgent == null ? "unknown" : userAgent;
  }

  /**
   * 获取浏览器版本
   *
   * @param request 请求对象
   * @return 浏览器字符串
   */
  public static String getStringBrowser(HttpServletRequest request) {
    String returnStr = "unknown";
    String userAgent = request.getHeader("user-agent");
    if (userAgent == null) {
      return returnStr;
    }
    int index = userAgent.indexOf("MSIE");
    if (index > -1) {
      returnStr = userAgent.substring(index).split(";")[0];
    } else {
      index = userAgent.indexOf("Chrome");
      if (index > -1) {
        returnStr = userAgent.substring(index).split(" ")[0];
      } else {
        index = userAgent.indexOf("Firefox");
        if (index > -1) {
          returnStr = userAgent.substring(index).split(" ")[0];
        }
      }
    }
    return returnStr;
  }

  /**
   * 获得客户端真实IP地址
   *
   * @param request 请求对象
   * @return 客户端ip地址
   */
  public static String getClientAddress(HttpServletRequest request) {
    String ip = request.getHeader("x-forwarded-for");
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getRemoteAddr();
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("http_client_ip");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("HTTP_X_FORWARDED_FOR");
    }
    // 如果是多级代理，那么取第一个ip为客户ip
    if (ip != null && ip.contains(",")) {
      ip = ip.substring(0, ip.lastIndexOf(",")).trim();
    }
    return ip;
  }

  /**
   * 判断ajax请求
   *
   * @param request 请求对象
   * @return 是/否
   */
  public static boolean isAjax(HttpServletRequest request) {
    return (request.getHeader("X-Requested-With") != null
        && "XMLHttpRequest".equals(request.getHeader("X-Requested-With")));
  }

  /**
   * 判定是不是api请求
   * @param request 请求对象
   * @return 是/否
   */
  public static boolean isApi(HttpServletRequest request) {
    return matches("/api*", getRelativeURI(request));
  }

  /**
   * 判断是否满足相关规则
   * <p/>
   * <p>
   * three type: endsWithMatch(eg. /xxx*=/xxx/xyz), startsWithMatch(eg. *.xxx=abc.xxx), equals(eg.
   * /xxx=/xxx).
   * </p>
   * <b>Notice</b>: *xxx* will match *xxxyyyy. endsWithMatch first.
   *
   * @param pattern 掩码
   * @param source 字符串
   * @return 是/否
   */
  public static boolean matches(String pattern, String source) {
    if (pattern == null || source == null) {
      return false;
    }
    pattern = pattern.trim();
    source = source.trim();
    if (pattern.endsWith("*")) {
      // pattern: /druid* source:/druid/index.html
      int length = pattern.length() - 1;
      if (source.length() >= length) {
        if (pattern.substring(0, length).equals(source.substring(0, length))) {
          return true;
        }
      }
    } else if (pattern.startsWith("*")) {
      // pattern: *.html source:/xx/xx.html
      int length = pattern.length() - 1;
      if (source.length() >= length && source.endsWith(pattern.substring(1))) {
        return true;
      }
    } else if (pattern.contains("*")) {
      // pattern: /druid/*/index.html source:/druid/admin/index.html
      int start = pattern.indexOf("*");
      int end = pattern.lastIndexOf("*");
      if (source.startsWith(pattern.substring(0, start))
          && source.endsWith(pattern.substring(end + 1))) {
        return true;
      }
    } else {
      // pattern: /druid/index.html source:/druid/index.html
      if (pattern.equals(source)) {
        return true;
      }
    }
    return false;
  }

  /**
   * 页面重定向
   *
   * @param request 请求对象
   * @param response 响应对象
   * @param relativeUrl 相对路径
   */
  public static void sendRedirect(HttpServletRequest request, HttpServletResponse response,
      String relativeUrl) {
    sendRedirect(request, response, relativeUrl, null);
  }

  /**
   * 页面重定向
   *
   * @param request 请求对象
   * @param response 响应对象
   * @param relativeUrl 相对路径
   * @param queryString 查询字符串
   */
  public static void sendRedirect(HttpServletRequest request, HttpServletResponse response,
      String relativeUrl, String queryString) {
    String url = WebUtil.makeUrl(request, relativeUrl, queryString);
    sendRedirect(response, url);
  }

  /**
   * 页面重定向
   *
   * @param response 响应对象
   * @param url 绝对路径
   */
  public static void sendRedirect(HttpServletResponse response, String url) {
    logger.debug("--> sendRedirect to url[{}]", url);
    try {
      response.sendRedirect(url);
    } catch (IOException e) {
      throw ExceptionUtil.unchecked(e);
    }
  }

  /**
   * 输出html
   *
   * @param response 响应对象
   * @param html 待输出html
   */
  public static void responseHTML(HttpServletResponse response, String html) {
    try {
      response.setCharacterEncoding("UTF-8");
      response.setContentType("text/html;charset=utf-8");
      try (PrintWriter out = response.getWriter()) {
        out.print(EncodeUtil.unEscapeHtml(html));
        out.flush();// 刷新缓冲区，把缓冲区的数据输出
        out.close();
      }
    } catch (IOException e) {
      logger.error("", e);
    }
  }

  /**
   * 输出文本信息
   *
   * @param response 响应对象
   * @param text 待输出文本
   */
  public static void responseText(HttpServletResponse response, String text) {
    try {
      response.setCharacterEncoding("UTF-8");
      response.setContentType("text/html;charset=utf-8");
      try (PrintWriter out = response.getWriter()) {
        out.print(text);
        out.flush();// 刷新缓冲区，把缓冲区的数据输出
        out.close();
      }
    } catch (IOException e) {
      logger.error("", e);
    }
  }

  /**
   * 取字符串值
   *
   * @param request 请求对象
   * @param paramName 参数名
   */
  public static String getString(HttpServletRequest request, String paramName) {
    String value = request.getParameter(paramName);
    if (value != null) {
      value = value.trim();
      if (value.equals("")) {
        value = null;
      }
    }
    return value;
  }

  /**
   * 获取当事人
   *
   * @param request 请求对象
   * @return 当事人
   */
  public static Object getPrincipal(HttpServletRequest request) {
    Principal principal = request.getUserPrincipal();
    if (principal == null) {
      return null;
    }
    return principal;
  }

}
